﻿using System;
using System.Collections.Generic;

using System.Web;
using StillVoiceCommon;
using Microsoft.ApplicationBlocks.Data;
using System.Data;
using System.Data.SqlClient;
using TN5Y;

namespace TeamTime.Classes.Workflow
{
    public class Workflow : DataTableRow
    {
        public Workflow() { this.initClass(TN5Y.Utilities.DBConnectionString, "Workflow.Workflow"); }
        internal List<Case> getOpenCases()
        {
            List<Case> cases = new List<Case>();

            string sql = "select ID from Workflow.[Case] c  " +
                 " where WorkflowID = @WorkflowID and CaseStatus = 'Open'";
            SqlDataReader dr = SqlHelper.ExecuteReader(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("WorkflowID", Convert.ToInt32(this.KeyValue)));
            while (dr.Read())
            {
                Case c = new Case();
                c.load(Convert.ToInt32(dr["ID"]));
                cases.Add(c);
            }
            return cases;
        }

        internal List<Transition> getTransitions()
        {
            List<Transition> transitions = new List<Transition>();

            string sql = "select ID from Workflow.Transition t  " +
                 " where WorkflowID = @WorkflowID ";
            SqlDataReader dr = SqlHelper.ExecuteReader(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("WorkflowID", Convert.ToInt32(this.KeyValue)));
            while (dr.Read())
            {
                Transition transition = new Transition();
                transition.load(Convert.ToInt32(dr["ID"]));
                transitions.Add(transition);
            }
            return transitions;
        }
    }
    public class Arc : DataTableRow
    {
        public Arc() { this.initClass(TN5Y.Utilities.DBConnectionString, "Workflow.Arc"); }
        internal void doTransition(Int64 caseID)
        {
            //◦Get a list of all places which input to the transition.
            //◦Check that each of these places has a token (an AND-join must have one token for each input place). 
            //If the correct number of tokens is found then: 
            //■enable the transition (create a new WORKITEM record).

            Transition transition = new Transition();
            transition.load(Convert.ToInt32(this.Fields["TransitionID"]));
            foreach (Arc arc in transition.getInwardArcs())
            {
                if (!arc.hasToken(caseID))
                {
                    return;
                }
            }
            //else... all have tokens
            transition.createWorkItem(caseID);
        }

        private bool hasToken(Int64 caseID)
        {
            string sql = "select isnull(t.ID,0) from Workflow.Token t " +
                            "inner join Workflow.Place p on  t.PlaceID = p.ID " +
                            "where p.ID = @PlaceID and t.CaseID = @CaseID ";
            Int64 tID = Convert.ToInt64(SqlHelper.ExecuteScalar(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("PlaceID", Convert.ToInt32(this.Fields["PlaceID"])),
                new SqlParameter("CaseID", caseID)));
            return (tID > 0);

        }
    }
    public class WorkItem : DataTableRow
    {
        public string CaseContext;
        public string TaskName;
        public WorkItem() { this.initClass(TN5Y.Utilities.DBConnectionString, "Workflow.WorkItem"); }
        public new void load(Int64 id)
        {
            base.load(id);
            System.Data.SqlClient.SqlDataReader dr = SqlHelper.ExecuteReader(TN5Y.Utilities.DBConnectionString, CommandType.Text,
                "select * from Workflow.ViewWorkItems where ID = " + id);
            if (dr.Read())
            {
                CaseContext = dr["Context"].ToString();
                TaskName = dr["TaskName"].ToString();

                //AmountGranted = Convert.ToDecimal(dr["AmountGranted"]);
                //ConsultantName = dr["Consultant"].ToString();
                //OfficeName = dr["Office"].ToString();
                //EnterpriseName = dr["CompanyName"].ToString();
            }
            dr.Close();
            dr = null;
        }


        internal void finish()
        {
            this.Fields["WorkItemStatus"] = "Finished";
            this.Fields["FinishedDate"] = DateTime.Now;
            this.updateWithUserIDDate();
        }

        internal void updateTokensOnInwardArcsStatus(string p)
        {
            foreach (Token token in this.getArcPlacesTokens())
            {
                token.Fields["TokenStatus"] = "Consumed";
                token.Fields["ConsumedDate"] = DateTime.Now;
                token.update();
            }
        }

        private List<Token> getArcPlacesTokens()
        {
            List<Token> tokens = new List<Token>();

            string sql = "select t.ID from Workflow.Arc a " +
                 " inner join Workflow.Place p on a.PlaceID = p.ID " +
                 " inner join Workflow.Token t on p.ID = t.PlaceID " +
                 " where a.Direction = 'IN' and a.TransitionID = @TransitionID";
            SqlDataReader dr = SqlHelper.ExecuteReader(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("TransitionID", Convert.ToInt32(this.Fields["TransitionID"])));
            while (dr.Read())
            {
                Token t = new Token();
                t.load(Convert.ToInt32(dr["ID"]));
                tokens.Add(t);
            }
            return tokens;
        }

        internal void createTokensOnOutwardArcPlaces(string guardExpression)
        {
            foreach (Place place in this.getOutwardArcPlaces(guardExpression))
            {
                place.addToken(Convert.ToInt64(this.Fields["CaseID"]));
            }
        }

        private List<Place> getOutwardArcPlaces(string guardExpression)
        {
            List<Place> places = new List<Place>();
            string sql = "select p.ID from Workflow.Arc a " +
                 " inner join Workflow.Place p on a.PlaceID = p.ID " +
                 " where a.Direction = 'OUT' and a.TransitionID = @TransitionID";
            if (guardExpression != "")
                sql += " and ArcType = 'Explicit OR split' and a.PreCondition = @GuardExpression ";
            SqlDataReader dr = SqlHelper.ExecuteReader(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("TransitionID", Convert.ToInt32(this.Fields["TransitionID"])),
                new SqlParameter("GuardExpression", guardExpression));


            while (dr.Read())
            {
                Place p = new Place();
                p.load(Convert.ToInt32(dr["ID"]));
                places.Add(p);
            }
            return places;

        }

        internal bool workItemExists()
        {
            throw new NotImplementedException();
        }

        internal void updateCaseExtraInfo()
        {
            Case wfcase = new Case();
            wfcase.load(Convert.ToInt32(this.Fields["CaseID"]));
            wfcase.populateExtraFields();
            wfcase.update();
        }
    }
    public class WorkItems
    {
        internal object search(string searchFor, string sortExpression, int userID, string caseStatus, Int32 officeID, int rowCount,
                                    string workItemStatus, bool usersRecordsOnly)
        {
            bool filterOnGroups = true;
            if (userID != 0)
            {
                if (usersRecordsOnly)
                {
                    filterOnGroups = false;
                }
                else
                {
                    User user = new User();
                    user.load(userID);
                    filterOnGroups = (!user.CanDo("ViewAllGroupsWorkItems"));
                }
            }
            string sql = "SELECT ";
            if (rowCount > 0) { sql += " TOP " + rowCount.ToString(); }
            sql += " wi.* FROM Workflow.ViewWorkItems wi";
            if (filterOnGroups)
            {
                sql += " inner join Security.[ViewUserGroupUsers] gu on wi.SecurityGroupID = gu.UserGroupID ";
                sql += " and gu.ID =  @UserID ";
            }
            


            sql += " where 1=1 ";
            if (searchFor != "")
            {
                sql += " and (wi.Narrative like '%'+@SearchFor+'%' ";
                sql += " or";
                sql += "  wi.TransitionName like '%'+@SearchFor+'%') ";
            }
            if (usersRecordsOnly)
            {
                sql += " and wi.UserIDAssigned = @UserID ";
            }
            if (workItemStatus != "Any")
            {
                sql += " and wi.WorkItemStatus = @WorkItemStatus ";
            }
            if (caseStatus != "Any")
            {
                sql += " and wi.CaseStatus = @CaseStatus ";
            }
            if (officeID != 0)
            {
                sql += " and wi.OfficeID = @OfficeID ";
            }

            if (sortExpression != "")
            {
                sql += " order by wi." + sortExpression;
            }
            return SqlHelper.ExecuteDataset(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                                new SqlParameter("SearchFor", searchFor),
                                new SqlParameter("WorkItemStatus", workItemStatus),
                                new SqlParameter("CaseStatus", caseStatus),
                                new SqlParameter("OfficeID", officeID),
                                new SqlParameter("UserID", userID));
        }



        internal bool workItemExists(long caseID, Int32 transitionID, string workItemStatus)
        {
            string sql = "select isnull(ID,0) from Workflow.WorkItem where CaseID = @CaseID and TransitionID = @TransitionID and WorkItemStatus = @WorkItemStatus";
            Int32 ID = Convert.ToInt32(SqlHelper.ExecuteScalar(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("CaseID", caseID),
                new SqlParameter("TransitionID", transitionID),
                new SqlParameter("WorkItemStatus", workItemStatus)));
            return (ID > 1);

        }
    }
    public class Transition : DataTableRow
    {
        public Transition()
        {
            this.initClass(TN5Y.Utilities.DBConnectionString, "Workflow.Transition");
        }
        public void fire()
        {

        }

        internal List<Arc> getInwardArcs()
        {
            List<Arc> arcs = new List<Arc>();

            string sql = "select ID from Workflow.Arc where TransitionID  = @TransitionID and Direction = 'IN'";
            SqlDataReader dr = SqlHelper.ExecuteReader(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("TransitionID", Convert.ToInt32(this.Fields["ID"])));

            while (dr.Read())
            {
                Arc arc = new Arc();
                arc.load(Convert.ToInt32(dr["ID"]));
                arcs.Add(arc);
            }
            return arcs;
        }

        internal void createWorkItem(long caseID)
        {
            WorkItems workItems = new WorkItems();
            if (!workItems.workItemExists(caseID, Convert.ToInt32(this.KeyValue), "Enabled"))
            {
                WorkItem workItem = new WorkItem();
                workItem.setForAdd();
                workItem.Fields["CaseID"] = caseID;
                workItem.Fields["TransitionID"] = this.KeyValue;
                workItem.Fields["WorkItemStatus"] = "Enabled";
                workItem.Fields["EnabledDate"] = DateTime.Now;

                workItem.update();

                //■If the transition trigger is 'AUTO' then process that TASK immediately, otherwise wait for some other trigger.
                if (this.Fields["TransitionTrigger"].ToString() == "Auto")
                {
                    Task task = new Task();
                    task.load(Convert.ToInt32(this.Fields["TaskID"]));
                    task.run();
                }
                //workItem.Fields["CancelledDate"] = this.txtCancelledDate.Text;
                //workItem.Fields["FinishedDate"] = this.txtFinishedDate.Text;
                //workItem.Fields["Deadline"] = this.txtDeadline.Text;
                //workItem.Fields["UserID"] = this.ddlUserID.SelectedValue;
            }
        }

        internal bool caseFulfillsConditions(Case wfcase)
        {
            bool ret = false;
            string sql = "select  a.ID, a.ArcType, a.PreCondition, case when tok.ID is null then 0 else 1 end  as HasToken " +
                        " from Workflow.Arc a  " +
                        " inner join Workflow.Place p on a.PlaceID = p.ID " +
                        " left join Workflow.Token tok on p.ID = tok.PlaceID and tok.CaseID = @CaseID " +
                        " where a.TransitionID = @TransitionID " +
                        " and a.Direction='IN' ";
            SqlDataReader dr = SqlHelper.ExecuteReader(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("TransitionID", Convert.ToInt32(this.Fields["ID"])),
                new SqlParameter("CaseID", Convert.ToInt64(wfcase.KeyValue)));

            //We make the assumption that the first of a set of arcs into a transition contains the correct Arc type (join/split)
            if (dr.Read())
            {
                //•SEQ - ordinary sequential flow, not a join or a split.
                //•Explicit OR split.
                //•Implicit OR split.
                //•OR join (explicit and implicit).
                //•AND split.
                //•AND join.
                //•SEQ - ordinary sequential flow, not a join or a split.
                //•Explicit OR split.
                //•Implicit OR split.
                //•OR join (explicit and implicit).
                //•AND split.
                //•AND join.
                string arcType = dr["ArcType"].ToString().ToUpper();
                switch (arcType)
                {
                    case "SEQ":
                        if (Convert.ToInt16(dr["HasToken"]) == 1)
                        {
                            ret = true;

                        }
                        break;
                    case "AND JOIN":
                        //Check for tokens in all places
                        while (dr.Read())
                        {
                            if (Convert.ToInt16(dr["HasToken"]) != 1)
                                break;
                        }
                        //...else
                        ret = true;
                        break;

                }

            }
            return ret;
        }
    }
    public class Place : DataTableRow
    {
        public Place() { this.initClass(TN5Y.Utilities.DBConnectionString, "Workflow.Place"); }
        internal void addToken(Int64 caseID)
        {

            Int32 placeID = Convert.ToInt32(this.KeyValue);
            Token token = new Token();
            token.setForAdd();
            //token.Fields["ID"] = this.ddlID.SelectedValue;
            token.Fields["CaseID"] = caseID;
            token.Fields["PlaceID"] = placeID;
            token.Fields["TokenStatus"] = "Free"; //•FREE - Free •LOCK - Locked •CONS - Consumed •CANC - Cancelled
            token.Fields["EnabledDate"] = DateTime.Now;
            try
            {
                token.update();
            }
            catch (Exception ex)
            {
                if (ex.Message.ToLower().Contains("cannot insert duplicate"))
                {
                    //Do nothng
                }
                else
                    throw ex;
            }
            //token.Fields["CancelledDate"] = this.txtCancelledDate.Text;
            //token.Fields["ConsumedDate"] = this.txtConsumedDate.Text;

            //Whenever a token is created in a place the following checks are made:
            //•If it is the end place then the CASE is closed.
            Case wfcase = new Case();
            wfcase.load(caseID);
            if (placeID == wfcase.getEndPlaceID())
            {
                wfcase.close();
            }
            else
            {
                //•Find all inward arcs which go from this place into a transition, and for each transition attempt to fire

                foreach (Arc arc in this.getArcsFromHereIntoTransitions())
                {
                    arc.doTransition(caseID);
                }

            }
        }

        private List<Arc> getArcsFromHereIntoTransitions()
        {
            List<Arc> arcs = new List<Arc>();

            string sql = "select ID from Workflow.Arc where PlaceID  = @PlaceID and Direction = 'IN'";
            SqlDataReader dr = SqlHelper.ExecuteReader(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("PlaceID", Convert.ToInt32(this.KeyValue)));

            while (dr.Read())
            {
                Arc arc = new Arc();
                arc.load(Convert.ToInt32(dr["ID"]));
                arcs.Add(arc);
            }
            return arcs;
        }
    }
    public class Case : DataTableRow
    {
        public Case()
        {
            this.initClass(TN5Y.Utilities.DBConnectionString, "Workflow.[Case]");
        }
        internal Place getStartPlace()
        {
            string sql = "select ID from Workflow.Place where PlaceType=1 /*start*/ and WorkflowID = @WorkflowID";
            int ID = Convert.ToInt32(SqlHelper.ExecuteScalar(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                                       new SqlParameter("WorkflowID", Convert.ToInt32(this.Fields["WorkflowID"]))));
            if (ID <= 0)
                throw new Exception("Workflow.Case.getStartPlace: No start Place record found for workflow with ID " + this.Fields["WorkflowID"].ToString());
            else
            {
                Place place = new Place();
                place.load(ID);
                return place;
            }
        }

        internal int getEndPlaceID()
        {
            string sql = "select ID from Workflow.[Place] where PlaceType=9 /*End place*/ and WorkflowID = @WorkflowID";
            int ID = Convert.ToInt32(SqlHelper.ExecuteScalar(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                                       new SqlParameter("WorkflowID", Convert.ToInt32(this.Fields["WorkflowID"]))));
            if (ID <= 0)
                throw new Exception("Workflow.Case.getStartPlace: No End place record found for workflow with ID " + this.Fields["WorkflowID"].ToString());
            else
            {
                return ID;
            }
        }

        internal void close()
        {
            this.Fields["CaseStatus"] = "Closed";
            this.Fields["EndDate"] = DateTime.Now;
            this.updateWithUserIDDate();
        }

        internal void populateExtraFields()
        {
            string[] ctxt = this.Fields["Context"].ToString().Split('~');
            if (ctxt[0] == "FundingApplication")
            {
                FundingApplication fundingApplication = new FundingApplication();
                fundingApplication.load(Convert.ToInt32(ctxt[2]));
                this.Fields["OfficeID"] = fundingApplication.Fields["OfficeID"];
                this.Fields["UserIDAssigned"] =  fundingApplication.getUserIDForConsultant();
                this.Fields["Narrative"] = fundingApplication.EnterpriseName;
                if (fundingApplication.FundingFor != "")
                    this.Fields["Narrative"] += " / " + fundingApplication.FundingFor;
                //if (fundingApplication.ConsultantName != "")
                  //  this.Fields["Narrative"] += " / " + fundingApplication.ConsultantName;
            }
        }
    }
    public class Token : DataTableRow { public Token() { this.initClass(TN5Y.Utilities.DBConnectionString, "Workflow.Token"); } }
    public class Task : DataTableRow
    {
        //public string TableName;
        //public string KeyFieldName;
        //public int KeyValue;
        public int WorkflowID;
        public string TaskName;
        public Task()
        { this.initClass(TN5Y.Utilities.DBConnectionString, "Workflow.Task"); }
        public void LoadByKey(string taskName)
        {
            //
            this.TaskName = taskName;
            string sql = "select ID from Workflow.Task where TaskName = @TaskName ";
            int ID = Convert.ToInt32(SqlHelper.ExecuteScalar(TN5Y.Utilities.DBConnectionString, CommandType.Text, sql,
                                    new SqlParameter("TaskName", taskName)));
            base.load(ID);

        }
        //
        //•Is the task a workitem in an existing case? 
        public WorkItem getExistingWorkItemInCase(string context) //string tableName, string keyFieldName, int keyValue)
        {
            WorkItem ret = null;
            //string sql = "select isnull(ID,0) from Workflow.WorkItem wi inner join Case c on wi.CaseID = c.ID " +
            //                "where c.WorkflowID = @WorkflowID and Context = @Context";
            string sql = "select isnull(wi.ID,0) from Workflow.WorkItem wi " +
                            " inner join Workflow.Transition t on wi.TransitionID = t.ID " +
                            " inner join Workflow.[Case] c on wi.CaseID = c.ID  " +
                            " where t.TaskID = @TaskID and c.Context = @Context and wi.WorkItemStatus ='Enabled'";
            int WorkItemID = Convert.ToInt32(SqlHelper.ExecuteScalar(Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("TaskID", this.KeyValue),
                new SqlParameter("Context", context))); //getWorkflowRecordContext(tableName,keyFieldName,keyValue)
            if (WorkItemID > 0)
            {
                WorkItem workItem = new WorkItem();
                workItem.load(WorkItemID);
                ret = workItem;
            }
            return ret;
        }


        internal void addNewCase(string context)
        {
            //◦A record will be added to the wf_case table using the current primary key as the value for context.
            //◦A record will be added to the wf_token table for the start place of this workflow.
            Case wfCase = new Case();
            wfCase.setForAdd();
            wfCase.Fields["WorkFlowID"] = this.Fields["WorkflowID"];
            wfCase.Fields["Context"] = context;
            wfCase.populateExtraFields();
            wfCase.Fields["CaseStatus"] = "Open";
            wfCase.Fields["StartDate"] = DateTime.Now;
            //wfCase.Fields["EndDate"] = this.txtEndDate.Text;
            wfCase.Fields["CreatedDate"] = DateTime.Now;
            wfCase.Fields["UserIDCreatedBy"] = this.UserIDModifiedBy;
            wfCase.Fields["RecordDate"] = DateTime.Now;

            wfCase.UserIDModifiedBy = this.UserIDModifiedBy;
            wfCase.updateWithUserIDDate();
            Place startPlace = wfCase.getStartPlace();
            startPlace.addToken(Convert.ToInt64(wfCase.KeyValue));
        }

        //internal bool newWorkflowCaseCriteriaFullfilled()
        //{
        //    throw new NotImplementedException();
        //}

        internal bool isStartTask()
        {
            bool ret = false;
            string sql = "select top 1 ID from Workflow.Workflow where TaskIDStartsWith = @TaskID";
            if (Convert.ToInt32(SqlHelper.ExecuteScalar(Utilities.DBConnectionString, CommandType.Text, sql,
                new SqlParameter("TaskID", this.KeyValue))) > 0)
            {
                ret = true;
            }
            return ret;
        }

        internal void run()
        {
            throw new NotImplementedException();
        }
    }

    public class Workflows
    {
        public string getWorkflowRecordContext(string tableName, string keyFieldName, int keyValue)
        {
            return tableName + "~" + keyFieldName + "~" + keyValue.ToString();
        }
        
        public void examineWorkflow(String taskName, string context, string guardExpression)
        {
            //$input may be an associative array containing the details of a single database occurrence, or a WHERE string which will be converted into an associative array. 
            //$errors will contain an array of error messages, and will be empty if no errors are detected. 
            //This is performed whenever a task (user transaction) completes successfully in order to find out one of the following: 
            //•Is the task a workitem in an existing case? If the answer is 'yes' then the following will be performed: 
            Task task = new Task(); task.LoadByKey(taskName);
            WorkItem workItem = task.getExistingWorkItemInCase(context);
            if (workItem != null) // Existing case
            {
                //◦The wf_workitem record will have its status updated to 'finished'.
                //◦Find all wf_token records which exist on inward arcs and update their status to 'consumed'.
                //◦Create new wf_token records on places that exist on outward arcs.
                workItem.updateCaseExtraInfo(); //In case the wfCase details have changed a bit.
                workItem.finish();

                workItem.updateTokensOnInwardArcsStatus("Consumed");
                workItem.createTokensOnOutwardArcPlaces(guardExpression);
            }

            else
            {
                //•Does the task start a new workflow case? If the answer is 'yes' then the following will be performed: 
                //◦A record will be added to the wf_case table using the current primary key as the value for context.
                //◦A record will be added to the wf_token table for the start place of this workflow.
                if (task.isStartTask())
                {
                    task.addNewCase(context);
                }
            }
        }

        public string getURLForAction(Int64 workItemID)
        {
            string url;
            
                WorkItem workItem = new WorkItem();
                workItem.load(workItemID);
                string[] ctxt = workItem.CaseContext.ToString().Split('~');
                
                switch (workItem.TaskName)
                {
                    case "BDF:Add price detail":
                    case "BDF:Add quote detail":
                    case "BDF:Assign BDF to BDC":
                        url = "FundingApplicationsForm.aspx?" + ctxt[1] + "=" + ctxt[2];
                        
                        break;
                    case "BDF:BDC approval of BDF":
                    case "BDF:Provincial Manager approval of BDF":
                    case "BDF:Head Office Admin approval of BDF":
                    case "BDF:Senior Head Office Admin approval of BDF":
                    case "BDF:General Manager approval of BDF":
                    case "BDF:Chief Executive approval of BDF":
                    case "BDF:Close BDF":
                        url = "FundingApplicationsForm.aspx?" + ctxt[1] + "=" + ctxt[2] + "&approv=" + workItem.TaskName;
                        break;
                    case "RFP:Capture RFP":
                    case "RFP:Upload proof of payment":
                    case "RFP:Capture amounts paid by SMME":
                    case "RFP:Upload evaluation form":
                    case "RFP:Allocate RFP to BDC":
                        url = "FundingApplicationsForm.aspx?mode=rfp&" + ctxt[1] + "=" + ctxt[2];
                        break;
                    case "RFP:BDC approve RFP":
                    case "RFP:BDC close RFP":
                    case "RFP:Provincial Manager approve RFP":
                    case "RFP:Head Office Administrator approve RFP":
                    case "RFP:Senior Head Office Administrator approve RFP":
                    case "RFP:General Manager approve RFP":
                    case "RFP:Chief Executive approve RFP":
                    case "RFP:Finance Administrator create payment":
                    case "RFP:Finance Manager release payment":
                        url = "FundingApplicationsForm.aspx?" + ctxt[1] + "=" + ctxt[2] + "&mode=rfp&approv=" + workItem.TaskName;
                        break;
                    default:
                        url = workItem.TaskName;
                        if (!url.EndsWith("?")) { url += "?"; }
                        url = url + ctxt[1] + "=" + ctxt[2];
                        break;
                }

            return url;
        }
    }
}